#include <syscall.h>
#include <task.h>
#include <logf.h>
#include <fs.h>
#include <memory32.h>

typedef int (*syscall_handler_t)(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3);

void serial_sys_logf(char *fmt, int arg)
{
    logf(fmt, arg);
}

static const syscall_handler_t syscall_handler_table[] = {
    [SYS_NR_SLEEP] = (syscall_handler_t)task_sys_sleep,
    [SYS_NR_GETPID] = (syscall_handler_t)task_sys_getpid,
    [SYS_NR_PRINTS] = (syscall_handler_t)serial_sys_logf,
    [SYS_NR_FORK] = (syscall_handler_t)task_sys_fork,
    [SYS_NR_EXECVE] = (syscall_handler_t)task_sys_execve,
    [SYS_NR_OPEN] = (syscall_handler_t)fs_sys_open,
    [SYS_NR_READ] = (syscall_handler_t)fs_sys_read,
    [SYS_NR_WRITE] = (syscall_handler_t)fs_sys_write,
    [SYS_NR_CLOSE] = (syscall_handler_t)fs_sys_close,
    [SYS_NR_LSEEK] = (syscall_handler_t)fs_sys_lseek,
};

void syscall(syscall_frame_t *frame)
{
    uint32_t size = sizeof(syscall_handler_table) / sizeof(syscall_handler_table[0]);
    if (frame->id < size)
    {
        syscall_handler_t handler = syscall_handler_table[frame->id];
        if (handler)
        {
            frame->eax = handler(frame->arg0, frame->arg1, frame->arg2, frame->arg3);
            return;
        }
    }

    frame->eax = -1;
    task_t *task = get_running_task();
    logf("task: %s syscall(%d) error!", task->name, frame->id);
}

int open(const char *name, int flag, ...)
{
    syscall_arg_t open_arg = { SYS_NR_OPEN, (int)name, flag, 0, 0 };
    _syscall(&open_arg);
}

int read(int file, char *str, int len)
{
    syscall_arg_t read_arg = { SYS_NR_OPEN, file, (int)str, len, 0 };
    _syscall(&read_arg);
}

int write(int file, char *str, int len)
{
    syscall_arg_t write_arg = { SYS_NR_OPEN, file, (int)str, len, 0 };
    _syscall(&write_arg);
}

int close(int file)
{
    syscall_arg_t close_arg = { SYS_NR_OPEN, (int)file, 0, 0, 0 };
    _syscall(&close_arg);
}

int lseek(int file, int offset, int start)
{
    syscall_arg_t lseek_arg = { SYS_NR_OPEN, file, offset, start, 0 };
    _syscall(&lseek_arg);
}